package no.sogl.importer;

import java.io.File;
import java.io.FileInputStream;
import java.util.Date;
import java.util.List;

import no.sogl.domain.Membership;
import no.sogl.domain.Person;
import no.sogl.domain.Tag;
import no.sogl.domain.Team;
import no.sogl.domain.TeamMember;
import no.sogl.reference.Gender;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.joda.time.DateTime;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

public class MemberImporter {
    private static final Log log = LogFactory.getLog(MemberImporter.class);
    private static AbstractApplicationContext ctx;
    private static final boolean dryRun = false;

    public static void main(String[] args) throws Exception {
        log.info("Starting importer");
        ctx = new ClassPathXmlApplicationContext(new String[] { "classpath:META-INF/spring/applicationContext.xml" });
        ctx.registerShutdownHook();
        MemberImporter importer = ctx.getBean(MemberImporter.class);
        importer.createTeams();
        importer.parseMembers();
        importer.assignPeopleToTeams();
    }

    public void createTeams() {
        if (Team.findTeamByNameEquals("Allidrett") == null) new Team("Allidrett", 3, 5).persist();
        if (Team.findTeamByNameEquals("1.-2. Klasse") == null) new Team("1.-2. Klasse", 6, 7).persist();
        if (Team.findTeamByNameEquals("3. Klasse") == null) new Team("3. Klasse", 8, 8).persist();
        if (Team.findTeamByNameEquals("4. Klasse") == null) new Team("4. Klasse", 9, 9).persist();
        if (Team.findTeamByNameEquals("11-16 år") == null) new Team("11-16 år", 10, 15).persist();
        if (Team.findTeamByNameEquals("Junior") == null) new Team("Junior", 16, 25).persist();
    }

    @Transactional
    public void assignPeopleToTeams() {
        for (Person person : Person.findAllPeople()) {
            if (person.getBirthYear() == null) continue;
            Team team = Team.findTeamByAge(2011 - person.getBirthYear());
            if (team == null) continue;
            boolean alreadyMember = false;
            for (TeamMember member : person.getTeamMemberships()) {
                if (member.getTeam().equals(team)) {
                    alreadyMember = true;
                    break;
                }
            }
            if (alreadyMember) continue;
            new TeamMember(person, team).persist();
        }
    }

    public void parseMembers() throws Exception {
        parseMembers("/Users/espenwest/Documents/sogl/medlemmerSogl20120228.xls", 1, "NIF", true, null, N3SPORTBUILDER);
//        parseMembers("/Users/espenwest/Documents/sogl/Allidrett17-1820111020.xls", 0, "Oppmann Allidrett1", false, null,
//            ALLIDRETTBUILDER);
//        parseMembers("/Users/espenwest/Documents/sogl/Allidrett18-1920111020.xls", 0, "Oppmann Allidrett2", false, null,
//            ALLIDRETTBUILDER);
//        parseMembers("/Users/espenwest/Documents/sogl/1-2klasse20111020.xls", 0, "Oppmann 1.-2. Klasse", false, 2005,
//            FIRST_SECOND_CLASS_BUILDER);
//        parseMembers("/Users/espenwest/Documents/sogl/3klasse20111110.xls", 0, "Oppmann 3. Klasse", false, 2003,
//            THIRD_CLASS_BUILDER);
//        parseMembers("/Users/espenwest/Documents/sogl/4klasse20111207.xls", 0, "Oppmann 4. Klasse", false, 2002,
//            FOURTH_CLASS_BUILDER);
//        parseMembers("/Users/espenwest/Documents/sogl/2kmgruppa2011rev4.xls", 0, "Oppmann 2 KM", false, 2001, TWO_KM_BUILDER);
//        parseMembers("/Users/espenwest/Documents/sogl/6klasserevnov2011.xls", 0, "Oppmann 3-5 KM", false, null, TWO_KM_BUILDER);
//        parseMembers("/Users/espenwest/Documents/sogl/karusellrenn2011.xls", 0, "Karusell 2011", false, null,
//         KARUSELL_BUILDER);
//        parseMembers("/Users/espenwest/Documents/sogl/karusellrenn2012.xls", 0, "Karusell 2012", false, null,
//            KARUSELL_BUILDER);
    }

    public void parseMembers(String fileName, int sheetNo, String tagName, boolean memberInfo, Integer defaultYearOfBirth,
            PersonEntry.Builder builder) throws Exception {
        HSSFWorkbook wb = new HSSFWorkbook(new FileInputStream(new File(fileName)));
        Sheet sheet = wb.getSheetAt(sheetNo);
        Tag tag = null;
        if (tagName != null) {
            tag = Tag.findTagByNameEquals(tagName);
            if (tag == null) {
                tag = new Tag();
                tag.setName(tagName);
                tag.persist();
            }
        }
        for (Row row : sheet) {
            try {
                parseMemberRow(row, tag, memberInfo, defaultYearOfBirth, builder);
            } catch (Exception e) {
                log.warn("Error parsing member", e);
            }
        }

    }

    @Transactional
    private PersonEntry parseMemberRow(Row row, Tag tag, boolean memberInfo, Integer defaultYearOfBirth,
            PersonEntry.Builder builder) {
        PersonEntry entry = builder.build(row);
        if (entry == null) return null;
        if (dryRun) {
            log.info(entry);
            return entry;
        }
        Person person = null;
        try {
            if (entry.getBirthDate() != null) {
                String initialized = Person.initialize(entry.getFirstName(), entry.getLastName(), entry.getBirthDate());
                List<Person> persons = Person.findPeopleByBirthDayEquals(entry.getBirthDate()).getResultList();
                for (Person p : persons) {
                    if (initialized.equals(p.getLongInitials())) {
                        person = p;
                        log.info("HIT (date):" + entry + " ---> " + person);
                        break;
                    }
                }
            }
            else if (entry.getBirthYear() != null || defaultYearOfBirth != null )
             {
                if (entry.getBirthYear() == null) entry.setBirthYear(defaultYearOfBirth);
                String initialized = Person.initialize(entry.getFirstName(), entry.getLastName(), entry.getBirthYear());
                for (Person p : Person.findPeopleByBirthYearEquals(entry.getBirthYear()).getResultList()) {
                    if (initialized.equals(p.getLongInitialsWithBirthYear())) {
                        person = p;
                        log.info("HIT (year):" + entry + " ---> " + person);
                        break;
                    }
                }
            } 
            if (person == null) person = new Person();
            if (StringUtils.hasText(entry.getAddress())) person.setAddress(entry.getAddress());
            if (StringUtils.hasText(entry.getParentNames())) person.setParentNames(entry.getParentNames());
            if (entry.getBirthDate() != null && person.getBirthDay() == null) {
                person.setBirthDay(entry.getBirthDate());
                person.setBirthYear(new DateTime(entry.getBirthDate()).getYear());
            }
            if (entry.getBirthYear() != null && person.getBirthYear() == null) person.setBirthYear(entry.getBirthYear());
            if (StringUtils.hasText(entry.getCity())) person.setCity(entry.getCity());
            if (StringUtils.hasText(entry.getComment())) person.setComment(entry.getComment());
            if (!CollectionUtils.isEmpty(entry.getEmails())) {
                for (String email : entry.getEmails()) {
                    if (person.getEmail() == null) person.setEmail(email);
                    else if (!person.getEmail().matches("(?is).*" + email + ".*"))
                        person.setEmail(person.getEmail() + "," + email);
                }
            }
            if (StringUtils.hasText(entry.getFirstName()) && !StringUtils.hasText(person.getFirstName()))
                person.setFirstName(entry.getFirstName());
            if (StringUtils.hasText(entry.getLastName()) && !StringUtils.hasText(person.getLastName()))
                person.setLastName(entry.getLastName());
            if (StringUtils.hasText(entry.getGender()) && person.getGender() == null)
                person.setGender(Gender.parse(entry.getGender()));
            if (!CollectionUtils.isEmpty(entry.getMobiles())) {
                for (String mobile : entry.getMobiles()) {
                    if (person.getMobile() == null) person.setMobile(mobile);
                    else if (!person.getMobile().matches("(?is).*" + mobile + ".*"))
                        person.setMobile(person.getMobile() + "," + mobile);
                }
            }
            if (!CollectionUtils.isEmpty(entry.getPhones())) {
                for (String phone : entry.getPhones()) {
                    if (person.getPhone() == null) person.setPhone(phone);
                    else if (!person.getPhone().matches("(?is).*" + phone + ".*"))
                        person.setPhone(person.getPhone() + "," + phone);
                }
            }
            if (StringUtils.hasText(entry.getPostNo())) person.setZipCode(entry.getPostNo());
            if (person.getId() == null) person.persist();
            else person = person.merge();
            person.addTag(tag);
            if (memberInfo) {
                Membership member = person.getMembership() != null ? person.getMembership() : new Membership();
                member.setActivatedAt(entry.getMemberSince() != null ? entry.getMemberSince() : new Date());
                member.setActive(true);
                member.setMemberSince(entry.getMemberSince() != null ? entry.getMemberSince() : new Date());
                member.setPerson(person);
                member.setN3sportId(entry.getN3sportId());
                if (member.getId() == null) member.persist();
                else member.merge();
            }
        } catch (Exception e) {
            log.warn("Error parsing person " + entry, e);
        }
        return entry;
    }

    private static final PersonEntry.Builder N3SPORTBUILDER = new PersonEntry.Builder().withN3sportIdCol(0)
        .withGenderCol(1)
        .withFirstNameCol(2)
        .withLastNameCol(3)
        .withBirthDateCol(4)
        .withPostNoCol(5)
        .withAddressCol(6)
        .withCityCol(8)
        .withEmailCol(10)
        .withJobPhoneCol(11)
        .withMobileCol(12)
        .withPhoneCol(13)
        .withMemberTypeCol(19)
        .withMainMemberIdCol(20)
        .withCommentCol(24)
        .withMemberSinceCol(28)
        .withPostAddressCol(32);
    private static final PersonEntry.Builder ALLIDRETTBUILDER = new PersonEntry.Builder().withFullNameCol(0)
        .withParentNamesCol(1)
        .withBirthDateCol(2)
        .withEmailCol(3)
        .withMobileCol(4)
        .withAddressCol(5)
        .withPostNoCol(6)
        .withCityCol(7);
    private static final PersonEntry.Builder FIRST_SECOND_CLASS_BUILDER = new PersonEntry.Builder().withFullNameCol(0)
        .withBirthDateCol(4)
        .withEmailCol(7)
        .withParentNamesCol(6)
        .withMobileCol(5)
        .withAddressCol(1)
        .withPostNoCol(2)
        .withCityCol(3)
        .withDateFormat("dd.MM.yy")
        .withDatesAsStrings(true);
    private static final PersonEntry.Builder THIRD_CLASS_BUILDER = new PersonEntry.Builder().withFullNameCol(0)
        .withAddressCol(1)
        .withPostNoCol(2)
        .withCityCol(3)
        .withBirthDateCol(4)
        .withMobileCol(5)
        .withParentNamesCol(6)
        .withEmailCol(7)
        .withDateFormat("dd.MM.yy")
        .withDatesAsStrings(true);;
    private static final PersonEntry.Builder FOURTH_CLASS_BUILDER = new PersonEntry.Builder().withFullNameCol(0)
        .withBirthDateCol(5)
        .withEmailCol(4)
        .withMobileCol(2)
        .withParentNamesCol(3)
        .withFullAddressCol(1);
    private static final PersonEntry.Builder TWO_KM_BUILDER = new PersonEntry.Builder().withFullNameCol(0)
        .withAddressCol(1)
        .withPostNoCol(2)
        .withCityCol(3)
        .withBirthDateCol(4)
        .withMobileCol(5)
        .withParentNamesCol(6)
        .withEmailCol(7)
        .withEmailCol(8)
        .withEmailCol(9);
    private static final PersonEntry.Builder KARUSELL_BUILDER = new PersonEntry.Builder().withFirstNameCol(1)
        .withLastNameCol(2)
        .withBirthYearCol(3)
        .withPhoneCol(4)
        .withGenderCol(5)
        .withEmailCol(6);

}
